﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Reflector;
using Reflector.CodeModel;
using Reflector.Graph.Graphs;
using System.IO;
using Reflector.CodeModel;

namespace MethodSeqGenerator
{
    //A DLLPreprocessor accepts a set of DLLs and gets all the external object types
    //from those DLLs
    class DLLPreprocessor
    {
        
        public static HashSet<String> namespaceList = null;
        public static HashSet<String> externalClassList = null;
        public static HashSet<String> declaredClassList = null;
        public static HashSet<String> declaredInterfaceList = null;
        IServiceProvider serviceProvider;
        ITranslatorManager translatorManager;

        /*public static DLLPreprocessor getInstance()
        {
            if (instance == null)
            {
                instance = new DLLPreprocessor();                
            }
            return instance;
        }*/

        public static void AddToExternalClassList(String extClassName, String namespaceStr)
        {
            if (!SeqGenUtil.IsPrimitiveType(extClassName) && !namespaceList.Contains(namespaceStr))
            {
                externalClassList.Add(extClassName);
            }
        }
        
        public DLLPreprocessor(IServiceProvider serviceProvider, ITranslatorManager translatorManager)
        {
            this.serviceProvider = serviceProvider;
            this.translatorManager = translatorManager;
            namespaceList = new HashSet<String>();
            externalClassList = new HashSet<String>();
            declaredClassList = new HashSet<String>();
            declaredInterfaceList = new HashSet<String>();
        }

        public void AnalyzeDll()
        {
            //Gather all namespaces
            DirectoryInfo directoryInfo = new DirectoryInfo(SeqGenerator.DLL_LOCATION_DIR);
            foreach (FileInfo fileInfo in directoryInfo.GetFiles())
            {
                GatherNamespacesAndClasses(SeqGenerator.DLL_LOCATION_DIR + "\\" + fileInfo.Name);
            }

            //Analyze all dlls to get external classes
            foreach (FileInfo fileInfo in directoryInfo.GetFiles())
            {
                AnalyzeDLLsForExternalClasses(SeqGenerator.DLL_LOCATION_DIR + "\\" + fileInfo.Name);
            }
        }

        public void GatherNamespacesAndClasses(String dllName)
        {
            IAssemblyManager assemblyManager = (IAssemblyManager)serviceProvider.GetService(typeof(IAssemblyManager));
            IAssembly assembly = assemblyManager.LoadFile(dllName);
            if (assembly != null)
            {
                foreach (IModule module in ((IAssembly)assembly).Modules)
                {
                    foreach (IType t in ((IModule)module).Types)
                    {
                        ITypeDeclaration td = (ITypeDeclaration)t;

                        //Capturing classes and interfaces
                        if (td.Interface)
                        {
                            declaredInterfaceList.Add(td.Namespace + "." + td.Name);
                        }
                        else
                        {
                            declaredClassList.Add(td.Namespace + "." + td.Name);
                        }
                        //End of the code for capturing classes and interfaces

                        String nsObj = td.Namespace;
                        if (nsObj != null && !nsObj.Equals(""))
                        {
                            namespaceList.Add(nsObj);
                        }
                    }
                }
            }
        }

        public void AnalyzeDLLsForExternalClasses(String dllName)
        {
            IAssemblyManager assemblyManager = (IAssemblyManager)serviceProvider.GetService(typeof(IAssemblyManager));
            IAssembly assembly = assemblyManager.LoadFile(dllName);
            if (assembly != null)
            {
                foreach (IModule module in ((IAssembly)assembly).Modules)
                {
                    foreach (IType t in ((IModule)module).Types)
                    {
                        ITypeDeclaration td = (ITypeDeclaration)t;

                        foreach (IMethodDeclaration imdObj in ((ITypeDeclaration)td).Methods)
                        {
                            try
                            {

                                IMethodDeclaration visitedMethod = this.translatorManager.CreateDisassembler(null, null)
                                                                        .TranslateMethodDeclaration(imdObj);
                                DeclarationVisitor dvObj = new DeclarationVisitor();
                                dvObj.VisitMethodDeclaration(visitedMethod);
                            }
                            catch (Exception ex)
                            {
                            }
                        }
                    }
                }
            }
        }
    }

    //A visitor method that visits variable and parameter declarations
    class DeclarationVisitor : Visitor
    {
        public override void VisitFieldDeclaration(IFieldDeclaration value)
        {
            try
            {
                ITypeReference typRef = value.FieldType as ITypeReference;
                DLLPreprocessor.AddToExternalClassList(typRef.Namespace.ToString() + "." + typRef.Name.ToString(), typRef.Namespace.ToString());
            }
            catch (Exception )
            {
            }
        }

        public override void VisitPropertyDeclaration(IPropertyDeclaration value)
        {
            try 
            {
                ITypeReference typRef = value.DeclaringType as ITypeReference; 
                DLLPreprocessor.AddToExternalClassList(typRef.Namespace.ToString() + "." + typRef.Name.ToString(), typRef.Namespace.ToString());
            }
            catch (Exception )
            {
            }
        }

        public override void VisitParameterDeclaration(IParameterDeclaration value)
        {
            try 
            {
                ITypeReference typRef = value.ParameterType as ITypeReference;
                DLLPreprocessor.AddToExternalClassList(typRef.Namespace.ToString() + "." + typRef.Name.ToString(), typRef.Namespace.ToString());
            }
            catch (Exception )
            {
            }
        }

        public override void VisitVariableDeclarationExpression(IVariableDeclarationExpression value)
        {
            try
            {
                ITypeReference typRef = value.Variable.VariableType as ITypeReference;            
                DLLPreprocessor.AddToExternalClassList(typRef.Namespace.ToString() + "." + typRef.Name.ToString(), typRef.Namespace.ToString());
            }
            catch (Exception )
            {
            }
        }
    }
}
